package com.spark.sniffer.plugin.plugins.interceptor;

import static com.spark.sniffer.tracing.Span.ERR_CODE;
import static com.spark.sniffer.tracing.Span.Type.WS;
import static java.util.stream.Collectors.joining;
import java.lang.reflect.Method;
import java.util.Map;
import com.spark.sniffer.logging.api.Logger;
import com.spark.sniffer.logging.api.LoggerFactory;
import com.spark.sniffer.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import com.spark.sniffer.plugin.interceptor.enhance.MethodInterceptResult;
import com.spark.sniffer.tracing.TracingContext;
import com.spark.sniffer.util.ReflectUtil;
import com.spark.sniffer.util.ReflectUtil.WrapperMethod;

public class AsyncHttpClientInterceptor implements InstanceMethodsAroundInterceptor {

  private static final Logger LOG = LoggerFactory.getLogger(AsyncHttpClientInterceptor.class);

  @Override
  public void beforeMethod(//
      Object instance, Method method, Object[] allArguments, //
      Class<?>[] argumentsTypes, MethodInterceptResult result //
  ) throws Throwable {
    TracingContext.getContext().startSpan(WS, method.getName());
    
    // 开始设置header
    // 设置透传数据
    Map<String, String> passHeader = TracingContext.getContext().getPassThroughMap();
    WrapperMethod addHeader = ReflectUtil.getMethod(instance, "addHeader", CharSequence.class, String.class);
    
    passHeader.forEach((key, value) -> addHeader.invoke(key, value));

    if (LOG.isDebugEnable()) {
      String headers = passHeader.entrySet().stream().map(entry -> {
        return entry.getKey() + "=" + entry.getValue();
      }).collect(joining(","));

      LOG.debug("pass through AsyncHttpClient headers: [{}]", headers);
    }
  }

  @Override
  public Object afterMethod( //
      Object instance, Method method, Object[] allArguments, //
      Class<?>[] argumentsTypes, Object ret //
  ) throws Throwable {
    if (TracingContext.getContext().getEntrance() != null) {
      TracingContext.getContext().stopSpan();
    }

    return ret;
  }

  @Override
  public void handleMethodException( //
      Object instance, Method method, Object[] allArguments, //
      Class<?>[] argumentsTypes, Throwable t //
  ) {
    TracingContext.getContext().setActiveSpanCode(ERR_CODE);
  }

}
